﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TipsForm.cs" company="TechBits">
//   Copyright (c) TechBits. All rights reserved.
// </copyright>
// <author>
//   Leandro G. Vacirca.
// </author>
// <summary>
//   Defines the TipsForm type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace IntelliShortCut.UI.Forms
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    using Properties;

    /// <summary>
    /// Tips form.
    /// </summary>
    public partial class TipsForm : InfoBaseForm
    {
        #region "Private Members"

        /// <summary>
        /// Saves the tip message per page.
        /// </summary>
        private readonly Dictionary<int, TipMessageData> _tipMessages = new Dictionary<int, TipMessageData>();

        /// <summary>
        /// Cursor to the current tip page.
        /// </summary>
        private static int _currentTipPage;

        #endregion

        #region "Constructors"

        /// <summary>
        /// Initializes a new instance of the <see cref="TipsForm"/> class.
        /// </summary>
        public TipsForm()
        {
            InitializeComponent();
            InitializeTipMessages();
        }

        #endregion

        #region "Enums"

        /// <summary>
        /// Defines the move actions of the tip pages.
        /// </summary>
        public enum MoveToTipPageEnum
        {
            /// <summary>
            /// First. Value = 0.
            /// </summary>
            First = 0,

            /// <summary>
            /// Previous. Value = 1.
            /// </summary>
            Previous = 1,

            /// <summary>
            /// Next. Value = 2.
            /// </summary>
            Next = 2,

            /// <summary>
            /// Last. Value = 3.
            /// </summary>
            Last = 3
        }

        /// <summary>
        /// Defines the align modes.
        /// </summary> 
        public enum InsertImageAlignEnum
        {
            /// <summary>
            /// Insert image before text. Value = 0.
            /// </summary>
            BeforeText = 0,

            /// <summary>
            /// Insert image after text. Value = 1.
            /// </summary>
            AfterText = 1
        }

        #endregion

        #region "Public Members"

        /// <summary>
        /// Gets WindowTittle.
        /// </summary>
        public static string WindowTittle
        {
            get
            {
                return "TechBits IntelliShortCut Help and Tips!";
            }
        }

        #endregion        

        #region "UI Events"

        /// <summary>
        /// Form load event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void TipsForm_Load(object sender, EventArgs e)
        {            
            // Show the first tip message
            MovesToTipPage(MoveToTipPageEnum.First);
        }

        /// <summary>
        /// Moves to the previous tip.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void PreviousTipButton_Click(object sender, EventArgs e)
        {
            MovesToTipPage(MoveToTipPageEnum.Previous);
        }

        /// <summary>
        /// Moves to the next tip.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void NextTipButton_Click(object sender, EventArgs e)
        {
            MovesToTipPage(MoveToTipPageEnum.Next);
        }

        /// <summary>
        /// Closes the tip window.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event parameters.</param>
        private void CloseTipsButton_Click(object sender, EventArgs e)
        {
            Close();
        }

        #endregion

        #region "Private Methods"

        /// <summary>
        /// Initialize all tip messages.
        /// </summary>
        private void InitializeTipMessages()
        {
            var tipMessage = new TipMessageData
             {
                 Message =
                     "\nIntelliShortCut can help you to run your most used programs easiest and faster than ever.\n\nThe application will start minimized to the tray and to show it simply press <h>Alt+Up</h> and to minimize it back to the tray press <h>Escape</h>.",
                 TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                 TipTextColor = Color.Black,
                 TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                 TipTokenColor = Color.Blue,
                 InsertImage = true,
                 Image = Resources.IntelliShortCut_DetailedMainWindow,
                 InsertImageAlign = InsertImageAlignEnum.AfterText
             };
            _tipMessages.Add(1, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "\nYou have two ways to add shortcuts.\n\nThe first one is right-clicking on any *.exe, *.lnk or folder. Then you can choose between <h>AddMe to IntelliShortCut...</h> or <h>AliasMe to IntelliShortCut...</h>. \n\n\"AddMe to IntelliShortCut...\" option will generate internally a shortcut with the name of the file or folder.",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_ShellContextMenu,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(2, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "\nThe \"AliasMe to IntelliShortCut...\" alternative will allow you to enter an alias name instead the file name of the file or folder.",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_AliasWindow,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(3, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "\nThe second way to add shortcuts is through the <h>ShortcutsEditor</h> (you can access to the ShortcutsEditor by pressing <h>Ctrol+Shift+E</h> or right-clicking on the IntelliShortCut tray icon and then clicking on ShortcutsEditor menu).\n\nYou have a <h>Search</h> button that will search for installed applications on Windows and also in the default ProgramFiles folder. Then you can select the shortcuts you want to add by activating the active checkbox and clicking on the <h>Save</h> button.\n\nThe ShortcutsEditor will also allow you to <h>view</h>, <h>edit</h> and <h>remove</h> shortcuts.",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_ShortcutsEditorWindow,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(4, tipMessage);

            tipMessage = new TipMessageData
            {
                 Message = "\nHow to use IntelliShortCut? =)\n\nOnce you have added shortcuts you may want to execute your favorite application, so: Press <h>Alt+Up</h> and start typing the name or alias of the shortcut to that application and then press <h>Enter</h>.\n\n<h>That's all. It's Done!</h>",
                 TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                 TipTextColor = Color.Black,
                 TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                 TipTokenColor = Color.Blue,
                 InsertImage = true,
                 Image = Resources.IntelliShortCut_AutoCompletionFeature,
                 InsertImageAlign = InsertImageAlignEnum.AfterText
                };
            _tipMessages.Add(5, tipMessage);            

            tipMessage = new TipMessageData
            {
                Message = "\nIntelliShortCut has different operation modes. Each mode will help you in particular matters.\n\n" +
                "<h>All Mode: </h>type <h>-a</h> or <h>.all</h> and the autocompletion list will be loaded with all shortctus.\n\n",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_AllModeActivation,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(6, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "<h>Files Mode: </h>type <h>-f</h> or <h>.files</h> and the autocompletion list will be loaded with shortcuts associated to executable files only.\n\n" +
                "This mode is usefull is you want to access to application shortcuts only.",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_FilesModeActivation,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(7, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "<h>Folder Mode: </h>type <h>-d</h> or <h>.folders</h> and the autocompletion list will be loaded with shortcuts associated to folders only.\n\n" +
                "<h>Special Mode: </h>type <h>-s</h> or <h>.special</h> and the autocompletion list will be loaded with special folders shortctus only.\n\n",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = false,
            };
            _tipMessages.Add(8, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "<h>Browser Mode: </h>type <h>-b</h> or <h>.browser</h> and the autocompletion list will be loaded with the file system directory structure and you will have an \"on the fly\" browser. For example, you can type \"c\" and then use the <h>arrows keys</h> to navigate through folders.\n\n",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_InLineBrowser,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(9, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "<h>Web Mode: </h>type <h>-w</h> or <h>.browser</h> and the autocompletion list will be loaded with shortcuts associated to urls only.\n\n",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_WebModeActivation,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(10, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "If you have forgotten the name of a shortcut, simply press the down arrow key to view a list of the most ranked shortcuts on the current mode.\n\n",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_ListFeature,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(11, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "If you want to make a Google search simply write <h>g:</h> and then what you want to search. IntelliShortCut will open your default browser with the result of your search.\n\n",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_GoogleSearch,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(12, tipMessage);

            tipMessage = new TipMessageData
            {
                Message = "If you want to open a website simply write <h>w:</h> and then the address <h>without http://www.</h>..\n\n",
                TipTextFont = new Font("Verdana", 13, FontStyle.Regular),
                TipTextColor = Color.Black,
                TipTokenFont = new Font("Verdana", 13, FontStyle.Bold),
                TipTokenColor = Color.Blue,
                InsertImage = true,
                Image = Resources.IntelliShortCut_OpenWebSites,
                InsertImageAlign = InsertImageAlignEnum.AfterText
            };
            _tipMessages.Add(13, tipMessage);   
        }

        /// <summary>
        /// Shows a tip message.
        /// </summary>
        /// <param name="tipMessageData">The tip Message Data.</param>
        /// <param name="clearTipsTextBox">True: clear the TipsTextBox; false otherwise.</param>
        /// <remarks>
        /// Use "<h>...</h>" to highlight a portion of text.
        /// </remarks>
        private void ShowTip(TipMessageData tipMessageData, bool clearTipsTextBox)
        {
            TipsTextBox.ReadOnly = false;

            var tipsTokens = Regex.Matches(tipMessageData.Message, @"<[^>]+>[^<]*</[^>]+>");
            var tipsText = new List<TipTokenData>();
            int length = 0;

            // Clears the text box
            if (clearTipsTextBox)
            {
                TipsTextBox.Clear();
            }

            // Checks if an image must be placed before the text message
            if (tipMessageData.InsertImage && tipMessageData.InsertImageAlign.Equals(InsertImageAlignEnum.BeforeText))
            {
                InsertImage(tipMessageData.Image);
                TipsTextBox.SelectedText = "\n\n";
            }

            foreach (Match tipToken in tipsTokens)
            {
                var textBeforeTipToken = tipMessageData.Message.Substring(length, tipToken.Index - length);
                length = tipToken.Index + tipToken.Length;

                tipsText.Add(new TipTokenData { Text = textBeforeTipToken, IsToken = false });
                tipsText.Add(new TipTokenData { Text = tipMessageData.Message.Substring(tipToken.Index, tipToken.Length), IsToken = true });
            }

            if (tipMessageData.Message.Length > length)
            {
                tipsText.Add(new TipTokenData { Text = tipMessageData.Message.Substring(length), IsToken = false });
            }

            foreach (var token in tipsText)
            {
                // Set the tokens default color and font
                TipsTextBox.SelectionAlignment = HorizontalAlignment.Left;
                TipsTextBox.SelectionColor = tipMessageData.TipTextColor;
                TipsTextBox.SelectionFont = tipMessageData.TipTextFont;

                if (token.IsToken)
                {
                    // Apply alternative color and font to highlight keyword
                    TipsTextBox.SelectionColor = tipMessageData.TipTokenColor;
                    TipsTextBox.SelectionFont = tipMessageData.TipTokenFont;
                }

                TipsTextBox.SelectedText = token.Text.Replace("<h>", string.Empty).Replace("</h>", string.Empty);                
            }

            // Checks if an image must be placed after the text message
            if (tipMessageData.InsertImage && tipMessageData.InsertImageAlign.Equals(InsertImageAlignEnum.AfterText))
            {
                TipsTextBox.SelectedText = "\n\n";
                InsertImage(tipMessageData.Image);
            }

            TipsTextBox.ReadOnly = true;
        }

        /// <summary>
        /// Inserts an image into the TipsTextBox.
        /// </summary>
        /// <param name="image">The image to insert.</param>
        private void InsertImage(Image image)
        {
            Clipboard.SetImage(image);
            
            // Get the format for the object type.
            DataFormats.Format myFormat = DataFormats.GetFormat(DataFormats.Bitmap);

            // After verifying that the data can be pasted, paste
            if (TipsTextBox.CanPaste(myFormat))
            {
                TipsTextBox.SelectionAlignment = HorizontalAlignment.Center;
                TipsTextBox.Paste(myFormat);
            }            
        }

        /// <summary>
        /// Moves the tip page to an specified direction.
        /// </summary>
        /// <param name="moveAction">The move action.</param>
        private void MovesToTipPage(MoveToTipPageEnum moveAction)
        {
            switch (moveAction)
            {
                case MoveToTipPageEnum.First:
                    {
                        _currentTipPage = 1;
                        PreviousTipButton.Enabled = false;
                        NextTipButton.Enabled = !(_currentTipPage == _tipMessages.Count);
                        ShowTip(_tipMessages[_currentTipPage], true);
                        break;
                    }

                case MoveToTipPageEnum.Last:
                    {
                        _currentTipPage = _tipMessages.Count;
                        PreviousTipButton.Enabled = !(_currentTipPage == 1);
                        NextTipButton.Enabled = false;
                        ShowTip(_tipMessages[_currentTipPage], true);
                        break;
                    }

                case MoveToTipPageEnum.Next:
                    {
                        if (_currentTipPage < _tipMessages.Count)
                        {
                            _currentTipPage++;
                            PreviousTipButton.Enabled = true;                            
                            NextTipButton.Enabled = !(_currentTipPage == _tipMessages.Count);
                            ShowTip(_tipMessages[_currentTipPage], true);
                        }

                        break;
                    }

                case MoveToTipPageEnum.Previous:
                    {
                        if (_currentTipPage > 1)
                        {
                            _currentTipPage--;
                            NextTipButton.Enabled = true;
                            PreviousTipButton.Enabled = !(_currentTipPage == 1);
                            ShowTip(_tipMessages[_currentTipPage], true);
                        }

                        break;
                    }
            }
        }

        #endregion
    }

    #region "Internal Classes"

    /// <summary>
    /// Defines the tip token data.
    /// </summary>
    internal class TipTokenData
    {
        /// <summary>
        /// Gets or sets Text.
        /// </summary>
        public string Text { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether IsToken.
        /// </summary>
        public bool IsToken { get; set; }
    }

    /// <summary>
    /// Defines the tip message data.
    /// </summary>
    internal class TipMessageData
    {
        /// <summary>
        /// Gets or sets Message.
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether InsertImage.
        /// </summary>
        public bool InsertImage { get; set; }

        /// <summary>
        /// Gets or sets InsertImageAlign.
        /// </summary>
        public TipsForm.InsertImageAlignEnum InsertImageAlign { get; set; }

        /// <summary>
        /// Gets or sets Image.
        /// </summary>
        public Bitmap Image { get; set; }

        /// <summary>
        /// Gets or sets TipTextFont.
        /// </summary>
        public Font TipTextFont { get; set; }

        /// <summary>
        /// Gets or sets TipTokenFont.
        /// </summary>
        public Font TipTokenFont { get; set; }

        /// <summary>
        /// Gets or sets TipTextColor.
        /// </summary>
        public Color TipTextColor { get; set; }

        /// <summary>
        /// Gets or sets TipTokenColor.
        /// </summary>
        public Color TipTokenColor { get; set; }
    }

    #endregion
}
